/*
 * Semaphore.h
 *
 *  Created on: Oct 28, 2013
 *      Author: m
 */

#ifndef SEMAPHORE_H_
#define SEMAPHORE_H_

#include <iostream>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <cstdlib>
#include <cerrno>
#include <cstring>
#include <unistd.h>
#include "../common/Exception.h"

namespace ipc
{

#define SEM_DONT_CARE 0
#define SEM_PERMS 0600

class Semaphore
{
private:

    /**
     * Estructura semun para los semop
     */
    union semnum
    {
        int val;
        struct semid_ds* buf;
        ushort* array;
    };

    int m_id;
    int m_semAmmount;

    Semaphore( int id, int semAmmount );
    static Semaphore _create( std::string file, int charKey, int semAmmount, int flags);

public:

    /**
	 * Construtor por defecto
	 */
    Semaphore();

    /**
     * Destructor
     */
    virtual ~Semaphore();

    /**
     * Permite inizializar un array de semaforos
     *
     * @param initialValue Valor inicial de los semáforos
     * @return this
     */
    Semaphore& initialize( int initialValue );

    /**
     * Wait en el semaforo
     *
     * @param index Posicion del semaforo en el array sobre el que hacer wait
     */
    void p( int index = 0 );

    /**
     * Signal
     *
     * @param index Posicion del semaforo en el array sobre el que hacer signal
     */
    void v( int index = 0 );

    /**
     * Alias de p
     *
     * @param pos indice del semaforo sobre el que hacer wait
     */
    void wait( int index = 0 );

    /**
     * Alias de v
     *
     * @param pos indice del semaforo sobre el que hacer signal
     */
    void signal( int index = 0 );

    /**
     * Metodo para crear un array de semaforos
     *
     * @param file Archivo base
     * @param charKey Caracter para usar como clave
     * @param semAmmount Cantidad de semaforos en el array
     * @param flags flags del array (no tocar)
     * @return El semaforo creado
     */
    static Semaphore create( std::string file, int charKey, int semAmmount = 1,
            int flags = IPC_CREAT | IPC_EXCL, int initialValue = 0 );

    /**
     * Metodo para obtener un array de semaforos (ya creado)
     *
     * @param file Archivo base
     * @param charKey Caracter para usar como clave
     * @return El semaforo
     */
    static Semaphore get( std::string file, int charKey, int semAmmount = 1);

    /**
     * Metodo para destruir un array de semaforos
     *
     * @param file Archivo base
     * @param charKey Caracter para usar como clave
     */
    static void destroy( std::string file, int charKey );

};

} /* namespace ipc */
#endif /* SEMAPHORE_H_ */
